﻿using Microsoft.Win32;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Windows.Forms.VisualStyles;
using Vanara.PInvoke;

namespace Angle.Krill.Utils
{
    internal class WindowsApiHelper
    {
        // 定义钩子回调函数的委托
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
        /// <summary>
        /// 当前活动窗口的句柄
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
        /// <summary>
        /// The handle of the desktop window
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll")]
        private static extern IntPtr GetDesktopWindow();
        // 定义PostMessage函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        // 常量定义
        public const uint WM_KEYDOWN = 0x100;

        // P/Invoke SetWindowsHookEx
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        // P/Invoke UnhookWindowsHookEx
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        // P/Invoke CallNextHookEx
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
        public static extern int SystemParametersInfo(int uAction, int uParam, StringBuilder lpvParam, int fuWinIni);
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool PtInRect(ref RECT r, System.Drawing.Point pt);
        /// <summary>
        /// 查找窗口
        /// </summary>
        /// <param name="lpClassName"></param>
        /// <param name="lpWindowName"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessageTimeout(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, int fuFlags, int uTimeout, out IntPtr lpdwResult);
        [DllImport("user32.dll")]
        public static extern bool EnumWindows(EnumWindowsProc callback, IntPtr extra);
        [DllImport("user32.dll")]
        public static extern bool SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
        // 定义 MSLLHOOKSTRUCT 结构体，与 C++ 的结构体相同
        [StructLayout(LayoutKind.Sequential)]
        public struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int x;
            public int y;
        }
        static int SMTO_NORMAL = 0x0000;
        static IntPtr workerw;
        // 键盘钩子标识
        static int WH_KEYBOARD_LL = 13;
        // 鼠标钩子标识
        static int WH_MOUSE_LL = 14;
        static int HC_ACTION = 0;
        static int HC_GETNEXT = 1;
        static int WM_MOUSEMOVE = 0x0200;
        static int MK_XBUTTON1 = 0x0020;
        static int WM_LBUTTONDOWN = 0x0201;
        static int WM_LBUTTONUP = 0x0202;
        static int MK_LBUTTON = 0x0001;
        static int WM_MOUSEWHEEL = 0x020A;
        public static IntPtr GetWorkerW()
        {
            IntPtr res = new IntPtr(0);
            IntPtr windowHandle = FindWindow("Progman", null);

            SendMessageTimeout(windowHandle, 0x52c, new IntPtr(0), new IntPtr(0), SMTO_NORMAL, 0x3e8, out res);
            EnumWindows(new EnumWindowsProc(EnumWindowsProcProc), res);

            Console.WriteLine(res);

            return windowHandle;
        }

        public static bool EnumWindowsProcProc(IntPtr hwnd, IntPtr extra)
        {
            IntPtr res = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);

            if (res != IntPtr.Zero)
            {
                workerw = FindWindowEx(new IntPtr(0), hwnd, "WorkerW", null);
            }

            return true;
        }

        public static void SetWinParent(IntPtr workerW)
        {
            if (workerW != IntPtr.Zero)
            {
                ShowWindow(workerw, 3);
                if (workerw != IntPtr.Zero)
                {
                    SetParent(workerW, workerw);
                }
            }
            else
            {
                Console.WriteLine("未找到 Window");
            }
        }

        public static bool ReWallpaper()
        {
            StringBuilder wallpaper = new StringBuilder(200);
            SystemParametersInfo(0x73, 200, wallpaper, 0);
            int ret = SystemParametersInfo(20, 1, wallpaper, 3);
            if (ret != 0)
            {
                RegistryKey hk = Registry.CurrentUser;
                RegistryKey run = hk.CreateSubKey(@"Control Panel\Desktop\");
                run.SetValue("Wallpaper", wallpaper.ToString());
                return true;
            }

            return false;
        }

        public static bool IsDesktop()
        {
            IntPtr hProgman = FindWindow("Progman", null);
            IntPtr hWorkerW = IntPtr.Zero;

            // Get and load the main List view window containing the icons.
            IntPtr hShellViewWin = FindWindowEx(hProgman, IntPtr.Zero, "SHELLDLL_DefView", null);
            if (hShellViewWin != IntPtr.Zero)
            {
                IntPtr hDesktopWnd = GetDesktopWindow();
                // When this fails (picture rotation is turned ON, toggledesktop shell cmd used ), then look for the WorkerW windows list to get the
                // correct desktop list handle.
                // As there can be multiple WorkerW windows, iterate through all to get the correct one
                do
                {
                    hWorkerW = FindWindowEx(hDesktopWnd, hWorkerW, "WorkerW", null);
                    hShellViewWin = FindWindowEx(hWorkerW, IntPtr.Zero, "SHELLDLL_DefView", null);
                } while (hShellViewWin != IntPtr.Zero && hWorkerW != IntPtr.Zero);
            }

            HWND hForegroundWindow = GetForegroundWindow();

            return hForegroundWindow == hWorkerW || hForegroundWindow == hProgman;
        }

        static IntPtr gHWnd;

        internal static bool StartForwardMouseKeyboardMessage(IntPtr hWnd)
        {
            gHWnd = hWnd;

            IntPtr hModule = GetModuleHandle(null);

            var vMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hModule, 0);
            if (vMouseHook == IntPtr.Zero)
            {
                return false;
            }

            var vKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, hModule, 0);
            return true;
        }

        private static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode == HC_ACTION)
            {
                // 处理鼠标消息
                Console.WriteLine("Mouse event captured!");
                // 将 LPARAM 转换为 MSLLHOOKSTRUCT
                MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));

                int lp = MAKELONG(hookStruct.pt.x, hookStruct.pt.y);
                IntPtr lPtr = new IntPtr(lp);

                if (IsDesktop())
                {

                    if (wParam == (IntPtr)WM_MOUSEMOVE)
                    {
                        PostMessage(gHWnd, (uint)wParam, (IntPtr)MK_XBUTTON1, lPtr);
                    }
                    else if (wParam == (IntPtr)WM_LBUTTONDOWN || wParam == (IntPtr)WM_LBUTTONUP)
                    {
                        PostMessage(gHWnd, (uint)wParam, (IntPtr)MK_LBUTTON, lPtr);
                    }
                    else if (wParam == (IntPtr)WM_MOUSEWHEEL)
                    {
                        // TODO:
                    }
                }
                else if (wParam == (IntPtr)WM_MOUSEMOVE)
                {
                    RECT rect;
                    GetWindowRect(GetForegroundWindow(), out rect);

                    if (!PtInRect(ref rect, new System.Drawing.Point(hookStruct.pt.x, hookStruct.pt.y)))
                    {
                        PostMessage(gHWnd, (uint)wParam, (IntPtr)MK_XBUTTON1, lPtr);
                    }
                }
            }

            return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
        }

        private static int MAKELONG(int highWord, int lowWord)
        {
            return (highWord << 16) | (lowWord & 0xFFFF);
        }

        private static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                // 处理鼠标消息
                Console.WriteLine("Keyboard event captured!");
            }
            return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
        }
    }
}
